// Copyright (C) 2004-2009
// Alex Turbov, Igor Veresov
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <boost/thread/unilock.hpp>

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/fusion/mpl/push_front.hpp>

#include <cxxabi.h>
#include <cassert>
#include <cstdlib>
#include <string>
#include <typeinfo>

using namespace boost;

/**
 * \brief Get type name as string
 */
template <typename T>
std::string type_name(const T&)
{
    int status;
    char* name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
    if (!status)
    {
        std::string result = name;
        free(name);
        return result;
    }
    return typeid(T).name();
}

BOOST_AUTO_TEST_CASE(test_lock_matrix_0)
{
    typedef details::unilock_interface_impl<default_scheduler<exclusive_lock> > impl;
    typedef fusion::result_of::at_c<impl::lock_params_type, 0>::type result_t;
        std::cout << type_name(result_t()) << std::endl;
}

/*BOOST_AUTO_TEST_CASE(test_lock_matrix_1)
{
    typedef details::lock_matrix<exclusive_lock::type, exclusive_lock::matrix_type> matrix_t;
    matrix_t m;

    BOOST_CHECK_EQUAL(m.is_locked(exclusive_lock::lock), false);
    BOOST_CHECK_EQUAL(m.can_lock(exclusive_lock::lock), true);
    m.lock(exclusive_lock::lock);
    BOOST_CHECK_EQUAL(m.is_locked(exclusive_lock::lock), true);
    BOOST_CHECK_EQUAL(m.can_lock(exclusive_lock::lock), false);
    m.unlock(exclusive_lock::lock);
    BOOST_CHECK_EQUAL(m.is_locked(exclusive_lock::lock), false);
    BOOST_CHECK_EQUAL(m.can_lock(exclusive_lock::lock), true);
}

BOOST_AUTO_TEST_CASE(test_lock_matrix_2)
{
    typedef details::lock_matrix<rw_lock::type, rw_lock::matrix_type> matrix_t;
    matrix_t m;

    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::read), false);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::write), false);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::read), true);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::write), true);
    m.lock(rw_lock::read);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::read), true);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::write), false);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::read), true);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::write), false);
    m.unlock(rw_lock::read);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::read), false);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::write), false);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::read), true);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::write), true);
    m.lock(rw_lock::write);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::read), false);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::write), true);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::read), false);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::write), false);
    m.unlock(rw_lock::write);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::read), false);
    BOOST_CHECK_EQUAL(m.is_locked(rw_lock::write), false);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::read), true);
    BOOST_CHECK_EQUAL(m.can_lock(rw_lock::write), true);
}*/
/*
BOOST_AUTO_TEST_CASE(test_unilock_iface_impl)
{
    details::unilock_interface_impl<default_scheduler<exclusive_lock> > l;
    l.lock(fusion::vector<exclusive_lock::type>(exclusive_lock::lock));
    l.unlock(fusion::vector<exclusive_lock::type>(exclusive_lock::lock));
}

BOOST_AUTO_TEST_CASE(test_unilock_iface_impl2)
{
    typedef details::unilock_interface_impl<parameterized_scheduler<default_scheduler<exclusive_lock>, int> > unilock_t;
    unilock_t l;
    typedef fusion::vector<int, exclusive_lock::type> lock_params_type;

    l.lock(fusion::vector<int, exclusive_lock::type>(123, exclusive_lock::lock));
    l.unlock(lock_params_type(123, exclusive_lock::lock));
}*/

BOOST_AUTO_TEST_CASE(test_unilock_0)
{
    typedef unilock<default_scheduler<exclusive_lock> > lock_t;
    lock_t l;
    l.lock(exclusive_lock::lock);
    l.unlock(exclusive_lock::lock);
}

#if 0

unilock<default_scheduler<exclusive_lock> > l;
l.lock();
l.unlock();

unilock<default_scheduler<rw_lock> > rwl;
rwl.lock(rw_lock::read);
rwl.unlock(rw_lock::read);

unilock<priority_scheduler<exclusive_lock> > l;
l.lock(priority::high);
l.unlock();

unilock<parameterized_scheduler<default_scheduler<exclusive_lock>, int> > l;
l.lock(123);
l.unlock(123);

unilock<parameterized_scheduler<priority_scheduler<rw_lock>, int> > l;
l.lock(123, priority::high, rw_lock::read);
l.unlock(123, rw_lock::read);

unilock<
    parameterized_scheduler<
        parameterized_scheduler<
            default_scheduler<rw_lock>
          , int
          >
      , char
      >
  > l;
l.lock('a', 123, rw_lock::write);
l.unlock('a', 123, rw_lock::write);


#endif


